/*=+--+=#=+--     Unmanned Aerial System Management Software      --+=#=+--+=#*\
|          Copyright (C) 2011 Regents of the University of Colorado.           |
|                             All Rights Reserved.                             |

     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License version 2 as
     published by the Free Software Foundation.

     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.

            Jack Elston                       Cory Dixon                        
|           elstonj@colorado.edu              dixonc@colorado.edu              |
|                                                                              |
\*=+--+=#=+--                 --+=#=+--+=#=+--                    --+=#=+--+=#*/

/*!
  \file layerList.cxx
  \author Cory Dixon
*/

#include <stdlib.h>
#include <stdio.h>

#include <gtk/gtkwidget.h>
#include "layerList.h"
#include "vcConfig.h"
#include "utilities.h"

/*<---Extern Variables---->*/
extern GuiStruct    guiStr;

LayerList::LayerList()
{
	layer_list = NULL;
	tree_model = NULL;
	treeview   = NULL;
}

LayerList::~LayerList()
{
	// tree_model
	if( tree_model )
		g_object_unref (tree_model);
	if( treeview )
		gtk_widget_destroy (GTK_WIDGET(treeview));
}


void LayerList::init()
{	
	if( !guiStr.vcgui ) {
		cout << "LayerList::init() -- guiStr.vcgui not defined" << endl;
		return;
	}
	
	layer_list = (GtkWidget *)gtk_builder_get_object(guiStr.vcgui->getBuilder(), "layer_list");
	if( !layer_list ) {
		cout << "LayerList::init() -- no layer list widget" << endl;
		return;
	}

	// create tree store model
	tree_model = gtk_tree_store_new (  NUM_COLUMNS,
	                                   G_TYPE_STRING,  // name
	                                   G_TYPE_BOOLEAN, // visible
	                                   G_TYPE_INT      // item ptr
	                                );

	// create tree view 
	treeview = GTK_TREE_VIEW(gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_model)));

	// setup tree functionality
	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW (treeview), FALSE);
	gtk_tree_view_set_grid_lines(GTK_TREE_VIEW (treeview), GTK_TREE_VIEW_GRID_LINES_NONE);
	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW (treeview), FALSE);
	gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (treeview), FALSE);
	//gtk_tree_view_set_reorderable(GTK_TREE_VIEW (treeview), FALSE);
	gtk_tree_view_set_enable_search(GTK_TREE_VIEW (treeview), FALSE);

	GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
	gtk_tree_selection_set_mode( selection, GTK_SELECTION_NONE);

	// draw the view of the tree
	format_treeview();
	setColor( GTK_WIDGET(treeview) );

	// add to container
	gtk_widget_show( GTK_WIDGET(treeview));
	gtk_container_add (GTK_CONTAINER (layer_list), GTK_WIDGET(treeview));
}

void LayerList::format_treeview()
{
	gint col_offset;
	GtkCellRenderer *renderer;

	// column for system parameter names 
	renderer = gtk_cell_renderer_text_new ();
	g_object_set (renderer, "xalign", 0.0, NULL);
	col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
			-1, "Layer", renderer, 
			"text", NAME_COLUMN,
			NULL);

	// visible column 
	renderer = gtk_cell_renderer_toggle_new ();
	g_object_set (renderer, "xalign", 1.0, NULL);
	col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
			-1, "Visible", renderer, 
			"active", VISIBLE_COLUMN,
			NULL);

	g_signal_connect (renderer, "toggled", G_CALLBACK (LayerList::item_toggled), this);
}

void LayerList::delLayer(GooCanvasItem *item)
{
	if( !item ) return;

	// get the iter of the elemet
	GtkTreeIter iter;
	gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree_model), &iter);

	if(valid && searchTree(item, iter) ){
		gtk_tree_store_remove(tree_model, &iter);
	}
}

void LayerList::setShown(GooCanvasItem *item, bool val)
{
	if( !item ) return;

	// get the iter of the elemet
	GtkTreeIter iter;

	gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree_model), &iter);

	// set this items visibility column
	if(valid && searchTree(item, iter) ){
		gtk_tree_store_set (tree_model, &iter,
				VISIBLE_COLUMN, val,
				-1);
	}

	if( (int64_t)item < (int64_t)GPSMap::NUM_LAYERS )
		return;
/*
	GtkTreeIter tmp_iter;
	bool hasParent = false;

	// now make sure top layer item is set
	valid = gtk_tree_model_iter_parent(GTK_TREE_MODEL (tree_model), &tmp_iter, &iter);
	while (valid) {
		hasParent = true;
		iter = tmp_iter;
		valid = gtk_tree_model_iter_parent(GTK_TREE_MODEL (tree_model), &tmp_iter, &iter);
	}
	if( hasParent )
		gtk_tree_store_set (tree_model, &iter, VISIBLE_COLUMN, val, -1);
*/
}


void LayerList::addLayer(String name, GooCanvasItem *item, GooCanvasItem *parent, const char *tooltip) 
{
	//cout << "LayerList::addLayer() - name=" << getFileName(name.c_str()) << " parent=" << parent << endl;
	if( !item ) return;

	string n = getFileName(name.c_str());

	GtkTreeIter iter;
	getIterFromParent(parent, iter);

	gtk_tree_store_set (tree_model, &iter,
			NAME_COLUMN, n.c_str(),
			VISIBLE_COLUMN, FALSE,
			ITEM_COLUMN, item,
			-1);
/*
	if(tooltip) {
		GtkTooltip tt;
		gtk_tooltip_set_text (&tt, tooltip);
		gtk_tree_view_set_tooltip_row(treeview, &tt, &iter );
	}
*/
}

bool LayerList::getIterFromParent(GooCanvasItem *parent, GtkTreeIter &iter) 
{
	GtkTreeIter p_iter;

	//if( (int)parent < (int)GPSMap::NUM_LAYERS ) {
		//gtk_tree_store_append (tree_model, &iter, NULL);
		//return false;
	//} 

	// we need to look for the parent pointer they gave us
	gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree_model), &p_iter);
	if( valid ) {
		// now do a depth-first search
		if( searchTree(parent, p_iter) ) {
			gtk_tree_store_append (tree_model, &iter, &p_iter);
			return true;
		}
	}
	// no list, or didn't find the parent, so just add it to the top level
	//cout << "LayerList::getIterFromParent -- we didn't find the parent= "<< parent << endl;
	gtk_tree_store_append (tree_model, &iter, NULL);

	return false;
}

bool LayerList::searchTree(GooCanvasItem *parent, GtkTreeIter &p_iter) 
{
	GtkTreeIter child_iter;
	GooCanvasItem *item;

	do {

		// get data from current row
		gtk_tree_model_get (GTK_TREE_MODEL (tree_model), &p_iter, ITEM_COLUMN, &item, -1);

		//cout << "LayerList::searchTree -- parent=" << parent << " item=" << item << endl;
		// if the current row is the parent
		if( item == parent ) {
			return true;
		}

		// see if the row has a child
		gboolean valid;
		if( gtk_tree_model_iter_has_child( GTK_TREE_MODEL (tree_model), &p_iter ) ) {
			valid = gtk_tree_model_iter_children( GTK_TREE_MODEL (tree_model), &child_iter, &p_iter);
			while (valid) {

				// depth-search of this element
				if( searchTree(parent,child_iter) ) {
					p_iter = child_iter;
					return true;
				}

				// didn't find the parent item, try next element in list
				valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (tree_model), &child_iter);
			}
		}

	} while ( gtk_tree_model_iter_next (GTK_TREE_MODEL (tree_model), &p_iter) );

	return false;
}

void LayerList::item_toggled (GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
{
	LayerList     * me = (LayerList *)data;
	GtkTreeModel  * model = GTK_TREE_MODEL(me->tree_model);
	GtkTreePath   * path = gtk_tree_path_new_from_string (path_str);
	GtkTreeIter     iter;

	gboolean        onOff;
	gchar         * name;
	GooCanvasItem * item_ptr;

	//cout << "LayerList::item_toggled: path=" << path_str << endl;

	// get toggled iter 
	gtk_tree_model_get_iter (model, &iter, path);

	// get data from current row
	gtk_tree_model_get (model, &iter, 
	                    NAME_COLUMN, &name,
	                    VISIBLE_COLUMN, &onOff,
	                    ITEM_COLUMN, &item_ptr,
	                    -1);

	if( item_ptr == NULL ) {
		cout << "LayerList::item_toggled - did not retrieve item pointer for layer list" << endl;
		// clean up 
		if(name) g_free (name);
		if(path) gtk_tree_path_free (path);
		return;
	}
		
	// do something with the value
	onOff ^= 1;

	// set new value 
	gtk_tree_store_set (GTK_TREE_STORE (model), &iter, VISIBLE_COLUMN, onOff, -1);
	
	// set visibility of item
	if( (int64_t)(item_ptr) < GPSMap::NUM_LAYERS ) {
		guiStr.config.gpsmap->toggleLayerShown( (GPSMap::GroupLayers)((int64_t)item_ptr), onOff);
	} else {
		if( onOff )
			g_object_set (item_ptr, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
		else
			g_object_set (item_ptr, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
	}

	// clean up 
	if(name) g_free (name);
	if(path) gtk_tree_path_free (path);
}
